package cn.csg.iotplatform.module.system.service.user;

import cn.csg.iotplatform.framework.common.constants.GlobalConstants;
import cn.csg.iotplatform.framework.common.constants.RedisCacheKey;
import cn.csg.iotplatform.framework.common.enums.CommonStatusEnum;
import cn.csg.iotplatform.framework.common.exception.ServiceException;
import cn.csg.iotplatform.framework.common.pojo.PageResult;
import cn.csg.iotplatform.framework.common.util.collection.CollectionUtils;
import cn.csg.iotplatform.framework.common.util.crypto.RSAUtil;
import cn.csg.iotplatform.framework.common.util.date.DateUtils;
import cn.csg.iotplatform.framework.common.util.object.BeanUtils;
import cn.csg.iotplatform.framework.datapermission.core.util.DataPermissionUtils;
import cn.csg.iotplatform.framework.mybatis.core.query.LambdaQueryWrapperX;
import cn.csg.iotplatform.framework.web.core.util.WebFrameworkUtils;
import cn.csg.iotplatform.module.infra.api.config.ConfigApi;
import cn.csg.iotplatform.module.infra.api.config.dto.ConfigDTO;
import cn.csg.iotplatform.module.infra.api.file.FileApi;
import cn.csg.iotplatform.module.infra.enums.ConfigKeyConstants;
import cn.csg.iotplatform.module.system.api.permission.dto.UserZoneDomainDto;
import cn.csg.iotplatform.module.system.api.user.dto.AdminUserDeptRespDTO;
import cn.csg.iotplatform.module.system.controller.admin.user.vo.profile.UserProfileUpdatePasswordReqVO;
import cn.csg.iotplatform.module.system.controller.admin.user.vo.profile.UserProfileUpdateReqVO;
import cn.csg.iotplatform.module.system.controller.admin.user.vo.user.*;
import cn.csg.iotplatform.module.system.convert.user.UserConvert;
import cn.csg.iotplatform.module.system.dal.dataobject.dept.DeptDO;
import cn.csg.iotplatform.module.system.dal.dataobject.dept.UserDeptRelationDto;
import cn.csg.iotplatform.module.system.dal.dataobject.dept.UserPostDO;
import cn.csg.iotplatform.module.system.dal.dataobject.dept.vo.DeptSearchVO;
import cn.csg.iotplatform.module.system.dal.dataobject.dict.DictDataDO;
import cn.csg.iotplatform.module.system.dal.dataobject.permission.RoleDO;
import cn.csg.iotplatform.module.system.dal.dataobject.permission.UserRoleDO;
import cn.csg.iotplatform.module.system.dal.dataobject.security.SecurityConfigDO;
import cn.csg.iotplatform.module.system.dal.dataobject.user.AdminUserDO;
import cn.csg.iotplatform.module.system.dal.mysql.dept.DeptMapper;
import cn.csg.iotplatform.module.system.dal.mysql.dept.UserPostMapper;
import cn.csg.iotplatform.module.system.dal.mysql.permission.RoleMapper;
import cn.csg.iotplatform.module.system.dal.mysql.permission.UserRoleMapper;
import cn.csg.iotplatform.module.system.dal.mysql.user.AdminUserMapper;
import cn.csg.iotplatform.module.system.enums.security.SecurityStatusEnum;
import cn.csg.iotplatform.module.system.enums.user.UserIdEnum;
import cn.csg.iotplatform.module.system.service.dept.DeptService;
import cn.csg.iotplatform.module.system.service.dept.PostService;
import cn.csg.iotplatform.module.system.service.dict.DictDataService;
import cn.csg.iotplatform.module.system.service.permission.PermissionService;
import cn.csg.iotplatform.module.system.service.permission.RoleService;
import cn.csg.iotplatform.module.system.service.security.SecurityConfigService;
import cn.csg.iotplatform.module.system.service.tenant.TenantService;
import cn.csg.iotplatform.module.system.util.ToolUtil;
import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.collection.CollectionUtil;
import cn.hutool.core.io.IoUtil;
import cn.hutool.core.util.StrUtil;
import com.alibaba.excel.util.StringUtils;
import com.alibaba.fastjson.JSONObject;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.google.common.annotations.VisibleForTesting;
import com.google.common.collect.Lists;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.cache.annotation.Cacheable;
import org.springframework.context.annotation.Lazy;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import javax.annotation.Resource;
import java.io.InputStream;
import java.time.LocalDateTime;
import java.util.*;
import java.util.function.Function;
import java.util.regex.Pattern;
import java.util.stream.Collectors;

import static cn.csg.iotplatform.framework.common.exception.util.ServiceExceptionUtil.exception;
import static cn.csg.iotplatform.framework.common.util.collection.CollectionUtils.convertList;
import static cn.csg.iotplatform.framework.common.util.collection.CollectionUtils.convertSet;
import static cn.csg.iotplatform.module.system.enums.ErrorCodeConstants.*;

/**
 * 后台用户 Service 实现类
 *
 * @author 芋道源码
 */
@Service("adminUserService")
@Slf4j
public class AdminUserServiceImpl implements AdminUserService {

    @Value("${sys.user.init-password:iotyuanma}")
    private String userInitPassword;

    @Resource
    private DeptService deptService;
    @Resource
    private PostService postService;
    @Resource
    private PermissionService permissionService;
    @Resource
    private PasswordEncoder passwordEncoder;
    @Resource
    @Lazy // 延迟，避免循环依赖报错
    private TenantService tenantService;
    @Resource
    private DictDataService dictDataService;

    @Resource
    private AdminUserMapper userMapper;
    @Resource
    private UserRoleMapper userRoleMapper;
    @Resource
    private UserPostMapper userPostMapper;
    @Resource
    private RoleMapper roleMapper;
    @Resource
    private DeptMapper deptMapper;
    @Resource
    private SecurityConfigService securityConfigService;

    @Resource
    private FileApi fileApi;

    @Resource
    private ConfigApi configApi;
    @Resource
    private RoleService roleService;

    @Override
    @Transactional(rollbackFor = Exception.class)
    public Long createUser(UserSaveReqVO createReqVO) {
        //1.校验账户配合
        this.tenantService.handleTenantInfo(tenant -> {
            long count = userMapper.selectCount();
            if (count >= tenant.getAccountCount()) {
                throw exception(USER_COUNT_MAX, tenant.getAccountCount());
            }
        });
        //2.校验正确性
        this.validateUserForCreateOrUpdate(null, createReqVO.getUsername(), createReqVO.getMobile(), createReqVO.getEmail(),
                createReqVO.getUserNo(), createReqVO.getDeptId(), createReqVO.getRelationDeptIds(), createReqVO.getPostIds(),
                createReqVO.getPassword());
        //3.插入用户信息
        AdminUserDO user = BeanUtils.toBean(createReqVO, AdminUserDO.class);
        user.setStatus(CommonStatusEnum.ENABLE.getStatus()); // 默认开启
        user.setPassword(encodePassword(createReqVO.getPassword())); // 加密密码
        log.info("用户性别：{}", user.getSex());

        // 默认用户首次登录
        user.setFirLogin(CommonStatusEnum.FIR_LOGIN.getStatus());

        user.setUpdatePasswordTime(LocalDateTime.now());
        userMapper.insert(user);
        //4.插入关联岗位
        if (CollectionUtil.isNotEmpty(user.getPostIds())) {
            this.userPostMapper.insertBatch(convertList(user.getPostIds(),
                    postId -> new UserPostDO().setUserId(user.getId()).setPostId(postId)));
        }
        //5.插入借调单位信息
        if (CollectionUtil.isNotEmpty(createReqVO.getRelationDeptIds())) {
            this.deptService.insertUserDeptRelationBatch(convertList(createReqVO.getRelationDeptIds(),
                    relationDeptId -> new UserDeptRelationDto().setUserId(user.getId()).setDeptId(relationDeptId)));
        }
        //6.领域分区默认授权
        //获取字典值(领域,分区)
        List<DictDataDO> cmDomains = this.dictDataService.getDictDataList(0, "CM_DOMAIN");
        List<DictDataDO> cmZones = this.dictDataService.getDictDataList(0, "CM_ZONE");

        Set<String> domains = cmDomains.stream().map(DictDataDO::getValue).collect(Collectors.toSet());
        Set<String> zones = cmZones.stream().map(DictDataDO::getValue).collect(Collectors.toSet());

        UserZoneDomainDto requestDto = new UserZoneDomainDto();
        requestDto.setZones(zones);
        requestDto.setDomains(domains);
        requestDto.setUserId(user.getId());
        this.permissionService.assignUserZoneDomains(requestDto);

        return user.getId();
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void updateUser(UserSaveReqVO updateReqVO) {

        //校验数据完整性
        validateDataIntegrity( updateReqVO );

        this.validateDesensitization(updateReqVO,true);
        updateReqVO.setPassword(null); // 特殊：此处不更新密码
        AdminUserDO userDO = userMapper.selectById(updateReqVO.getId());
        if (userDO == null) {
            throw exception(USER_NOT_EXISTS);
        }
        //1.校验正确性
        this.validateUserForCreateOrUpdate(updateReqVO.getId(), updateReqVO.getUsername(), updateReqVO.getMobile(), updateReqVO.getEmail(),
                updateReqVO.getUserNo(), updateReqVO.getDeptId(), updateReqVO.getRelationDeptIds(), updateReqVO.getPostIds(), updateReqVO.getPassword());
        //2.更新用户
        AdminUserDO updateObj = BeanUtils.toBean(updateReqVO, AdminUserDO.class);

        if(userDO.getIsValid() == 0 && updateObj.getIsValid() == 1) {
            updateObj.setLoginDate(LocalDateTime.now());
        }
        userMapper.updateById(updateObj);
        //3.更新岗位
        this.updateUserPost(updateReqVO, updateObj);
        //4.更新借调单位信息
        this.updateRelationDept(updateReqVO, updateObj);

    }

    @Override
    public void validateDesensitization(UserSaveReqVO updateReqVO,boolean ignore) {
        AdminUserDO userDO = userMapper.selectById(updateReqVO.getId());
        if (userDO == null) {
            throw exception(USER_NOT_EXISTS);
        }
        if(StrUtil.hide(userDO.getNickname(),1,userDO.getNickname().length()).equals(updateReqVO.getNickname())){
            if(ignore){
                updateReqVO.setNickname(null);
            }else updateReqVO.setNickname(userDO.getNickname());
        }
        if(StringUtils.isNotBlank(updateReqVO.getElink()) && StrUtil.hide(userDO.getElink(),1,userDO.getElink().length()).equals(updateReqVO.getElink())){
            if(ignore){
                updateReqVO.setElink(null);
            }else updateReqVO.setElink(userDO.getElink());
        }
        if(StringUtils.isNotBlank(updateReqVO.getUserNo()) && StrUtil.hide(userDO.getUserNo(),1,userDO.getUserNo().length()).equals(updateReqVO.getUserNo())){
            if(ignore){
                updateReqVO.setUserNo(null);
            }else updateReqVO.setUserNo(userDO.getUserNo());
        }
        if(StringUtils.isNotBlank(updateReqVO.getMobile()) && StrUtil.hide(userDO.getMobile(),3,userDO.getMobile().length()).equals(updateReqVO.getMobile())){
            if(ignore){
                updateReqVO.setMobile(null);
            }else updateReqVO.setMobile(userDO.getMobile());
        }
        if(StringUtils.isNotBlank(updateReqVO.getEmail()) && StrUtil.hide(userDO.getEmail(),3,userDO.getEmail().length()).equals(updateReqVO.getEmail())){
            if(ignore) {
                updateReqVO.setEmail(null);
            }else updateReqVO.setEmail(userDO.getEmail());
        }
    }

    private void validateDataIntegrity(UserSaveReqVO updateReqVO) {

        SecurityConfigDO securityConfigDO = securityConfigService.getByClientId(updateReqVO.getClientId());

        //获取到加密后的数据，进行解密、解析
        String encryptionData = updateReqVO.getEncryptionData();
        String decrypt = RSAUtil.decrypt(encryptionData, securityConfigDO.getPrivateKey());

        JSONObject data = JSONObject.parseObject(decrypt);

        //根据字段用户账号、工号、手机号、邮箱、elink账号判断是否是数据完整性
        AdminUserDO userDO = userMapper.selectById(updateReqVO.getId());
        if (userDO.getId() == 1){
            //超级管理员，不给予修改
            throw exception(USER_ADMIN_CAN_NOT_UPDATE);
        }

        //由于加密的数据可能为未脱敏数据，需要先脱敏再比对
        String elink = data.getString( "elink" );
        if(StringUtils.isNotBlank(data.getString( "elink" )) && StrUtil.hide(userDO.getElink(),1,userDO.getElink().length()).equals(data.getString( "elink" ))){
            elink = userDO.getElink();
        }
        String userNo = data.getString( "userNo" );
        if(StringUtils.isNotBlank(data.getString( "userNo" )) && StrUtil.hide(userDO.getUserNo(),1,userDO.getUserNo().length()).equals(data.getString( "userNo" ))){
            userNo = userDO.getUserNo();
        }
        String mobile = data.getString( "mobile" );
        if(StringUtils.isNotBlank(data.getString( "mobile" )) && StrUtil.hide(userDO.getMobile(),3,userDO.getMobile().length()).equals(data.getString( "mobile" ))){
            mobile = userDO.getMobile();
        }
        String email = data.getString( "email" );
        if(StringUtils.isNotBlank(data.getString( "email" )) && StrUtil.hide(userDO.getEmail(),3,userDO.getEmail().length()).equals(data.getString( "email" ))){
            email = userDO.getEmail();
        }

        String encryptionDataStr = data.getString( "username" ) + "_" +
                userNo + "_" +
                mobile + "_" +
                email + "_" +
                elink;

        String paramsDataStr = updateReqVO.getUsername() + "_" +
                updateReqVO.getUserNo() + "_" +
                updateReqVO.getMobile() + "_" +
                updateReqVO.getEmail() + "_" +
                updateReqVO.getElink();

        if ( !encryptionDataStr.equals( paramsDataStr ) ){
            throw exception( "数据完整性校验不通过，无法提交" );
        }

    }

    @Override
    public List<AdminUserDeptRespDTO> getUserDeptList(Collection<Long> ids) {
        return userMapper.getUserDeptList(ids);
    }

    private void updateRelationDept(UserSaveReqVO reqVO, AdminUserDO updateObj) {
        Long userId = reqVO.getId();
        Set<Long> dbDeptIds = convertSet(this.deptService.queryUserDeptRelation(userId), UserDeptRelationVo::getDeptId);
        //1.计算新增和删除的借调单位id
        Set<Long> deptIds = CollUtil.emptyIfNull(updateObj.getRelationDeptIds());
        Collection<Long> createDeptIds = CollUtil.subtract(deptIds, dbDeptIds);
        Collection<Long> deleteDeptIds = CollUtil.subtract(dbDeptIds, deptIds);
        //2.执行新增和删除
        if (!CollectionUtil.isEmpty(createDeptIds)) {
            this.deptService.insertUserDeptRelationBatch(convertList(createDeptIds,
                    relationDeptId -> new UserDeptRelationDto().setUserId(userId).setDeptId(relationDeptId)));
        }
        if (!CollectionUtil.isEmpty(deleteDeptIds)) {
            this.deptService.deleteByUserIdAndDeptIds(userId, deleteDeptIds);
        }
    }

    private void updateUserPost(UserSaveReqVO reqVO, AdminUserDO updateObj) {
        Long userId = reqVO.getId();
        Set<Long> dbPostIds = convertSet(this.userPostMapper.selectListByUserId(userId), UserPostDO::getPostId);
        //1.计算新增和删除的岗位编号
        Set<Long> postIds = CollUtil.emptyIfNull(updateObj.getPostIds());
        Collection<Long> createPostIds = CollUtil.subtract(postIds, dbPostIds);
        Collection<Long> deletePostIds = CollUtil.subtract(dbPostIds, postIds);
        //2.执行新增和删除。对于已经授权的菜单，不用做任何处理
        if (!CollectionUtil.isEmpty(createPostIds)) {
            this.userPostMapper.insertBatch(convertList(createPostIds,
                    postId -> new UserPostDO().setUserId(userId).setPostId(postId)));
        }
        if (!CollectionUtil.isEmpty(deletePostIds)) {
            this.userPostMapper.deleteByUserIdAndPostId(userId, deletePostIds);
        }
    }

    @Override
    public void updateUserLogin(Long id, String loginIp) {
        userMapper.updateById(new AdminUserDO().setId(id).setLoginIp(loginIp).setLoginDate(LocalDateTime.now()));
    }

    @Override
    public void updateUserProfile(Long id, UserProfileUpdateReqVO reqVO) {
        // 校验正确性
        validateUserExists(id);
        validateEmailUnique(id, reqVO.getEmail());
        validateMobileUnique(id, reqVO.getMobile());
        // 执行更新
        userMapper.updateById(BeanUtils.toBean(reqVO, AdminUserDO.class).setId(id));
    }

    @Override
    public void updateUserPassword(Long id, UserProfileUpdatePasswordReqVO reqVO) {
        //解密前端加密密码
        decryptPassword(reqVO);
        // 校验旧密码密码
        validateOldPassword(id, reqVO.getOldPassword());
        // 执行更新
        AdminUserDO updateObj = new AdminUserDO().setId(id);
        updateObj.setPassword(encodePassword(reqVO.getNewPassword())); // 加密密码
        updateObj.setUpdatePasswordTime(LocalDateTime.now());
        updateObj.setFirLogin(0);
        userMapper.updateById(updateObj);
    }

    private void decryptPassword(UserProfileUpdatePasswordReqVO reqVO) {
        try{
            SecurityConfigDO securityConfigDO = securityConfigService.getByClientId(reqVO.getClientId());
            if(securityConfigDO == null) throw exception(CLIENT_ID_NOT_EXISTS);
            if(SecurityStatusEnum.isDisable(securityConfigDO.getStatus())) throw exception(CLIENT_ID_NOT_DISABLE);
            reqVO.setOldPassword(RSAUtil.decrypt(reqVO.getOldPassword(),securityConfigDO.getPrivateKey()));
            reqVO.setNewPassword(RSAUtil.decrypt(reqVO.getNewPassword(),securityConfigDO.getPrivateKey()));
        }catch (Exception e){
            log.error("解密密码异常",e);
        }
    }


    @Override
    public String updateUserAvatar(Long id, InputStream avatarFile) {
        validateUserExists(id);
        // 存储文件
        String avatar = fileApi.createFile(IoUtil.readBytes(avatarFile));
        // 更新路径
        AdminUserDO sysUserDO = new AdminUserDO();
        sysUserDO.setId(id);
        sysUserDO.setAvatar(avatar);
        userMapper.updateById(sysUserDO);
        return avatar;
    }

    @Override
    public void updateUserPassword(Long id, String password) {
        // 校验用户存在
        //validateUserExists(id);
        AdminUserDO adminUserDO = validateUserExistsAndReturn(id);

        boolean matches = passwordEncoder.matches(password, adminUserDO.getPassword());
        if (matches){
            throw exception(USER_SAME_OLD_PASSWORD);
        }

        // 更新密码
        AdminUserDO updateObj = new AdminUserDO();
        updateObj.setId(id);
        updateObj.setPassword(encodePassword(password)); // 加密密码
        userMapper.updateById(updateObj);
    }

    @Override
    public void updateUserStatus(Long id, Integer status) {
        // 校验用户存在
        validateUserExists(id);
        // 更新状态
        AdminUserDO updateObj = new AdminUserDO();
        updateObj.setId(id);
        updateObj.setStatus(status);
        userMapper.updateById(updateObj);
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void deleteUser(Long id) {
        //1.校验用户存在
        this.validateUserExists(id);
        //校验删除的是否超级管理员，超级管理员不可删除
        this.validateIsSuperAdmin(id);
        //校验用户存在关联角色
//        this.validateUserRole(id);
        //2.删除用户
        this.userMapper.deleteById(id);
        //3.删除用户关联数据
        this.permissionService.processUserDeleted(id);
        //4.删除用户岗位
        this.userPostMapper.deleteByUserId(id);
        //5.删除用户借调关系
        this.deptService.deleteByUserIdAndDeptIds(id, null);
    }

    /**
     * 校验删除的是否超级管理员，超级管理员不可删除
     * @param id
     */
    public void validateIsSuperAdmin(Long id){
        if (roleMapper.selectSuperAdminRoleByUserId(id) > 0) {
            throw exception(USER_ADMIN_CAN_NOT_DELETE);
        }
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void deleteBatchUser(Set<Long> ids) {
        Long loginUserId = WebFrameworkUtils.getLoginUserId();
        if (ids.contains(loginUserId) || ids.contains(1L)){
            throw exception(FORBID_DELETING_ONESELF);
        }
        ids.forEach(this::deleteUser);
    }

    @Override
    public AdminUserDO getUserByUsername(String username) {
        return userMapper.selectByUsername(username);
    }

    @Override
    public AdminUserDO getUserByMobile(String mobile) {
        return userMapper.selectByMobile(mobile);
    }

    @Override
    public PageResult<AdminUserDO> getUserPage(UserPageReqVO reqVO) {
        boolean includeChildDept = Optional.ofNullable(reqVO.getIncludeChildDept()).orElse(true);
        if( !roleService.isSuperAdmin() && !roleService.hasSelfAndChildDeptDataScope(WebFrameworkUtils.getLoginUserId())){
            includeChildDept = false;
        }
        if(includeChildDept && reqVO.getDeptId() == GlobalConstants.TOP_DEPT_ID){
            return userMapper.selectPage(reqVO, Lists.newArrayList());
        }
        List<Long> deptIds;
        if(includeChildDept){
            deptIds = deptService.getChildDeptTreeWithUserAttr(reqVO.getDeptId());
        }else deptIds = Lists.newArrayList(reqVO.getDeptId());
        return userMapper.selectPage(reqVO, deptIds);
    }

    /**
     * @param id
     * @return
     */
    @Override
    @Cacheable(cacheNames = RedisCacheKey.SYS_USER_NICK_NAME_KEY, key = "#id")
    public String getCacheUserNickName(Long id) {
        if (id == null) {
            return null;
        }
        AdminUserDO userDO = this.userMapper.selectById(id);
        return userDO == null ? (id + "") : userDO.getNickname();
    }


    @Override
    public PageResult<UserRespVO> queryUserPage(UserPageReqVO pageReqVO) {
        //1.获得用户分页列表
        PageResult<AdminUserDO> pageResult = this.getUserPage(pageReqVO);
        if (CollUtil.isEmpty(pageResult.getList())) {
            return new PageResult<>(pageResult.getTotal());
        }
        //2.获取部门数据(获取查询到的用户的部门
        Map<Long, DeptDO> deptMap = deptService.getDeptMap(convertList(pageResult.getList(), AdminUserDO::getDeptId));
        //3.拼接部门数据
        List<UserRespVO> userRespVOs = UserConvert.INSTANCE.convertList(pageResult.getList(), deptMap);
        //4.数据返回
        return new PageResult<>(userRespVOs, pageResult.getTotal());
    }

    @Override
    public List<UserDeptRelationVo> queryUserDeptRelation(Long id) {
        return this.deptService.queryUserDeptRelation(id);
    }

    @Override
    public AdminUserDO getUser(Long id) {
        return userMapper.selectById(id);
    }

    @Override
    public UserRespVO getUserInfo(Long id) {
        AdminUserDO user = this.getUser(id);
        // 拼接数据
        DeptDO dept = deptService.getDept(user.getDeptId());
        return UserConvert.INSTANCE.convert(user, dept);
    }

    @Override
    public List<AdminUserDO> getUserListByDeptIds(Collection<Long> deptIds) {
        if (CollUtil.isEmpty(deptIds)) {
            return Collections.emptyList();
        }
        return userMapper.selectListByDeptIds(deptIds);
    }

    @Override
    public List<AdminUserDO> getUserListByPostIds(Collection<Long> postIds) {
        if (CollUtil.isEmpty(postIds)) {
            return Collections.emptyList();
        }
        Set<Long> userIds = convertSet(userPostMapper.selectListByPostIds(postIds), UserPostDO::getUserId);
        if (CollUtil.isEmpty(userIds)) {
            return Collections.emptyList();
        }
        return userMapper.selectBatchIds(userIds);
    }

    @Override
    public List<AdminUserDO> getUserList(Collection<Long> ids) {
        if (CollUtil.isEmpty(ids)) {
            return Collections.emptyList();
        }
        return userMapper.selectBatchIds(ids);
    }

    @Override
    public List<AdminUserDO> getAllUserList(Collection<Long> ids) {
        if (CollUtil.isEmpty(ids)) {
            return Collections.emptyList();
        }
        return userMapper.getAllUserListByIds(ids);
    }

    @Override
    public void validateUserList(Collection<Long> ids) {
        if (CollUtil.isEmpty(ids)) {
            return;
        }
        // 获得岗位信息
        List<AdminUserDO> users = userMapper.selectBatchIds(ids);
        Map<Long, AdminUserDO> userMap = CollectionUtils.convertMap(users, AdminUserDO::getId);
        // 校验
        ids.forEach(id -> {
            AdminUserDO user = userMap.get(id);
            if (user == null) {
                throw exception(USER_NOT_EXISTS);
            }
            if (!CommonStatusEnum.ENABLE.getStatus().equals(user.getStatus())) {
                throw exception(USER_IS_DISABLE, user.getNickname());
            }
        });
    }

    @Override
    public List<AdminUserDO> getUserListByNickname(String nickname) {
        return userMapper.selectListByNickname(nickname);
    }

    @Override
    public List<AdminUserDO> getAllUserListByNickname(String nickname) {
        return userMapper.selectAllUserListByNickname(nickname);
    }
    /**
     * 获得部门条件：查询指定部门的子部门编号们，包括自身
     *
     * @param deptId 部门编号
     * @return 部门编号集合
     */
    private Set<Long> getDeptCondition(Long deptId) {
        if (deptId == null) {
            return Collections.emptySet();
        }
        Set<Long> deptIds = convertSet(deptService.getChildDeptList(deptId), DeptDO::getId);
        deptIds.add(deptId); // 包括自身
        return deptIds;
    }

    private void validateUserForCreateOrUpdate(Long id, String username, String mobile, String email, String userNo,
                                               Long deptId, Set<Long> relationDeptIds, Set<Long> postIds, String password) {
        // 关闭数据权限，避免因为没有数据权限，查询不到数据，进而导致唯一校验不正确
        DataPermissionUtils.executeIgnore(() -> {
            // 校验用户存在
            this.validateUserExists(id);
            // 校验用户名唯一
            this.validateUsernameUnique(id, username);
            //校验密码强度
            this.validatePasswrod(password);
            // 校验手机号唯一
            this.validateMobileUnique(id, mobile);
            // 校验邮箱唯一
            this.validateEmailUnique(id, email);
            // 校验工号唯一
            this.validateUserNoUnique(id, userNo);
            // 校验部门处于开启状态
            this.deptService.validateDeptList(CollectionUtils.singleton(deptId));
            // 校验借调部门处于开启状态
            this.deptService.validateDeptList(relationDeptIds);
            // 校验岗位处于开启状态
            this.postService.validatePostList(postIds);

        });
    }

    /**
     * 验证密码长度与是否至少包含字母数字特殊符号中的2种
     *
     * @param password
     * @return
     */
    public void validatePasswrod(String password) {
        if (StrUtil.isBlank(password)) {
            return;
        }
        if (password.length() < 8 || password.length() > 16) {
            throw exception(USER_PASSWORD_LENGTH_FAILED);
        }

        int count = 0;

        // 检查密码中是否包含字母
        if (Pattern.matches(".*[a-zA-Z]+.*", password)) {
            count++;
        }

        // 检查密码中是否包含数字
        if (Pattern.matches(".*\\d+.*", password)) {
            count++;
        }

        // 检查密码中是否包含特殊字符
        if (Pattern.matches(".*[@#$%^&+=]+.*", password)) {
            count++;
        }

        if (count <= 1) {
            throw exception(USER_PASSWORD_STRENGTH_FAILED);
        }
    }

    @VisibleForTesting
    private void validateUserNoUnique(Long id, String userNo) {
        if (StrUtil.isBlank(userNo)) {
            return;
        }
        AdminUserDO user = userMapper.selectByUserNo(userNo);
        if (user == null) {
            return;
        }
        // 如果 id 为空，说明不用比较是否为相同 id 的用户
        if (id == null) {
            throw exception(USER_NO_NOT_EXISTS);
        }
        if (!user.getId().equals(id)) {
            throw exception(USER_NO_NOT_EXISTS);
        }
    }

    @VisibleForTesting
    void validateUserExists(Long id) {
        if (id == null) {
            return;
        }
        AdminUserDO user = userMapper.selectById(id);
        if (user == null) {
            throw exception(USER_NOT_EXISTS);
        }
    }

    AdminUserDO validateUserExistsAndReturn(Long id) {
        if (id == null) {
            throw exception(USER_NOT_EXISTS);
        }
        AdminUserDO user = userMapper.selectById(id);
        if (user == null) {
            throw exception(USER_NOT_EXISTS);
        }
        if (user.getId() == UserIdEnum.SUPERADMIN.getUserId()){
            throw exception(USER_NOT_EXISTS);
        }
        return user;
    }

    @VisibleForTesting
    void validateUserRole(Long id) {
        if (id == null) {
            return;
        }
        List<UserRoleDO> userRoleDOS = userRoleMapper.selectListByUserId(id);
        if (userRoleDOS.size() != 0) {
            throw exception(USER_ROLE_EXISTS);
        }
    }

    @VisibleForTesting
    void validateUsernameUnique(Long id, String username) {
        if (StrUtil.isBlank(username)) {
            return;
        }
        AdminUserDO user = userMapper.selectByUsername(username);
        if (user == null) {
            return;
        }
        // 如果 id 为空，说明不用比较是否为相同 id 的用户
        if (id == null) {
            throw exception(USER_USERNAME_EXISTS);
        }
        if (!user.getId().equals(id)) {
            throw exception(USER_USERNAME_EXISTS);
        }
    }

    @VisibleForTesting
    void validateEmailUnique(Long id, String email) {
        if (StrUtil.isBlank(email)) {
            return;
        }
        AdminUserDO user = userMapper.selectByEmail(email);
        if (user == null) {
            return;
        }
        // 如果 id 为空，说明不用比较是否为相同 id 的用户
        if (id == null) {
            throw exception(USER_EMAIL_EXISTS);
        }
        if (!user.getId().equals(id)) {
            throw exception(USER_EMAIL_EXISTS);
        }
    }

    @VisibleForTesting
    void validateMobileUnique(Long id, String mobile) {
        if (StrUtil.isBlank(mobile)) {
            return;
        }
        AdminUserDO user = userMapper.selectByMobile(mobile);
        if (user == null) {
            return;
        }
        // 如果 id 为空，说明不用比较是否为相同 id 的用户
        if (id == null) {
            throw exception(USER_MOBILE_EXISTS);
        }
        if (!user.getId().equals(id)) {
            throw exception(USER_MOBILE_EXISTS);
        }
    }

    /**
     * 校验旧密码
     *
     * @param id          用户 id
     * @param oldPassword 旧密码
     */
    @VisibleForTesting
    void validateOldPassword(Long id, String oldPassword) {
        AdminUserDO user = userMapper.selectById(id);
        if (user == null) {
            throw exception(USER_NOT_EXISTS);
        }
        if (!isPasswordMatch(oldPassword, user.getPassword())) {
            throw exception(USER_PASSWORD_FAILED);
        }
    }

    @Override
    @Transactional(rollbackFor = Exception.class) // 添加事务，异常则回滚所有导入
    public UserImportRespVO importUserList(List<UserImportExcelVO> importUsers, boolean isUpdateSupport) {
        if (CollUtil.isEmpty(importUsers)) {
            throw exception(USER_IMPORT_LIST_IS_EMPTY);
        }
        UserImportRespVO respVO = UserImportRespVO.builder().createUsernames(new ArrayList<>())
                .updateUsernames(new ArrayList<>()).failureUsernames(new LinkedHashMap<>()).build();
        importUsers.forEach(importUser -> {
            // 校验，判断是否有不符合的原因
            try {
                validateUserForCreateOrUpdate(null, null, importUser.getMobile(), importUser.getEmail(),
                        null, importUser.getDeptId(), null, null, null); //TODO 借调部门
            } catch (ServiceException ex) {
                respVO.getFailureUsernames().put(importUser.getUsername(), ex.getMessage());
                return;
            }
            // 判断如果不存在，在进行插入
            AdminUserDO existUser = userMapper.selectByUsername(importUser.getUsername());
            if (existUser == null) {
                userMapper.insert(BeanUtils.toBean(importUser, AdminUserDO.class)
                        .setPassword(encodePassword(userInitPassword)).setPostIds(new HashSet<>())); // 设置默认密码及空岗位编号数组
                respVO.getCreateUsernames().add(importUser.getUsername());
                return;
            }
            // 如果存在，判断是否允许更新
            if (!isUpdateSupport) {
                respVO.getFailureUsernames().put(importUser.getUsername(), USER_USERNAME_EXISTS.getMsg());
                return;
            }
            AdminUserDO updateUser = BeanUtils.toBean(importUser, AdminUserDO.class);
            updateUser.setId(existUser.getId());
            userMapper.updateById(updateUser);
            respVO.getUpdateUsernames().add(importUser.getUsername());
        });
        return respVO;
    }

    @Override
    public List<AdminUserDO> getUserListByStatus(Integer status) {
        return userMapper.selectListByStatus(status);
    }

    @Override
    public boolean isPasswordMatch(String rawPassword, String encodedPassword) {
        return passwordEncoder.matches(rawPassword, encodedPassword);
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void batchImport(List<UserImportExcelDto> list) {
        List<UserSaveReqVO> userSaveReqVOS = this.setUserSaveReqVO(list);
        log.info("Excel原始数据：{}", userSaveReqVOS);
        Set<Long> userIds = new HashSet<>();
        userSaveReqVOS.forEach(reqVo -> {
            List<DeptDO> deptDOS = this.deptMapper.selectList(new LambdaQueryWrapperX<DeptDO>()
                    .eq(DeptDO::getName, reqVo.getDeptName())
                    .eq(DeptDO::getDeleted, 0));
            if (ToolUtil.isNotEmpty(deptDOS)) {
                reqVo.setDeptId(deptDOS.get(0).getId());
            }
            Long userId = this.createUser(reqVo);
            userIds.add(userId);
            //解析权限数据,导入时关联上     - 2024.03.27 by Mr.Z
            Set<String> roleNames = new HashSet<>(this.handleStringsParam(reqVo.getRoleNames()));
            if (ToolUtil.isNotEmpty(roleNames)) {
                List<RoleDO> roleDOS = this.roleMapper.selectList(new LambdaQueryWrapperX<RoleDO>()
                        .in(RoleDO::getName, roleNames)
                        .eq(RoleDO::getDeleted, 0));
                if (ToolUtil.isNotEmpty(roleDOS)) {
                    Set<Long> roleIds = roleDOS.stream().map(RoleDO::getId).collect(Collectors.toSet());
                    this.permissionService.assignUserRole(userId, roleIds);
                }
            }

        });
        log.info("用户导入结果:应导入{}条,实际成功{}条", list.size(), userIds.size());
        log.info("成功导入的用户ids:{}", JSONObject.toJSON(userIds));
    }

    private List<UserSaveReqVO> setUserSaveReqVO(List<UserImportExcelDto> list) {
        List<UserSaveReqVO> resultList = new ArrayList<>();
        list.forEach(v -> {
            UserSaveReqVO userSaveReqVO = new UserSaveReqVO();
            //属性赋值
            userSaveReqVO.setUsername(v.getUsername());
            userSaveReqVO.setNickname(v.getNickname());
            userSaveReqVO.setRemark(v.getRemark());
            userSaveReqVO.setDeptId(v.getDeptId());
            userSaveReqVO.setEmail(v.getEmail());
            userSaveReqVO.setMobile(v.getMobile());
            userSaveReqVO.setElink(v.getElink());
            userSaveReqVO.setExpirationDate(v.getExpirationDate());
            userSaveReqVO.setUserNo(v.getUserNo());
            userSaveReqVO.setPassword(v.getPassword());
            userSaveReqVO.setDeptName(v.getDeptName());

            switch (v.getIsTenant()) {
                case "租户类型":
                    userSaveReqVO.setIsTenant(1);
                    break;
                case "非租户类型":
                    userSaveReqVO.setIsTenant(0);
                    break;
                default:
                    break;
            }

            switch (v.getSex()) {
                case "男":
                    userSaveReqVO.setSex(2);
                    break;
                case "女":
                    userSaveReqVO.setSex(1);
                    break;
                case "其他":
                    userSaveReqVO.setSex(0);
                    break;
                default:
                    break;
            }

            switch (v.getIsValid()) {
                case "有效":
                    userSaveReqVO.setIsValid(1);
                    break;
                case "无效":
                    userSaveReqVO.setIsValid(0);
                    break;
                default:
                    break;
            }

            //权限相关
            userSaveReqVO.setRoleNames(v.getRoleNames());

            resultList.add(userSaveReqVO);
        });

        return resultList;
    }

    /**
     * 格式化字符串参数
     * 示例:
     * param - aa-bb-cc-dd
     * param2 - list[aa,bb,cc,dd]
     *
     * @param param 原始入参
     * @return List<param> 格式化后的参数list
     */
    private List<String> handleStringsParam(String param) {
        if (ToolUtil.isEmpty(param)) {
            return new ArrayList<>();
        }
        return Arrays.asList(param.split("-"));
    }

    @Override
    public void copyUserRoles(CopyUsersRolesDto dto) {
/*        //1.获取当前登录用户权限ids
        Long loginUserId = WebFrameworkUtils.getLoginUserId();
        Set<Long> myRoleIds = this.permissionService.getUserRoleIdListByUserId(loginUserId);
        //2.获取赋值用户权限ids
        Set<Long> otherRoleIds = this.permissionService.getUserRoleIdListByUserIds(dto.getUserIds());
        //3.计算新增的权限ids
        Collection<Long> createRoleIds = CollUtil.subtract(otherRoleIds, myRoleIds);
        //4.执行新增
        if (!CollectionUtil.isEmpty(createRoleIds)) {

        }*/

    }

    @Override
    public UserStatRespVO getUserStat(UserPageReqVO reqVO) {
        ConfigDTO configDTO = configApi.getConfig(ConfigKeyConstants.ACTIVE_USER_LOGIN_TIMES).getData();
        reqVO.setActiveUserLoginTimes(Integer.parseInt(configDTO.getValue()));
        reqVO.setNet(reqVO.getDeptId().equals(GlobalConstants.TOP_DEPT_ID));
        return userMapper.getUserStat(reqVO);
    }

    @Override
    public PageResult<UserStatDetailRespVO> getUserStatDetail(UserPageReqVO reqVO) {
        IPage<UserStatDetailRespVO> page = new Page<>(reqVO.getPageNo(), reqVO.getPageSize());
        ConfigDTO configDTO = configApi.getConfig(ConfigKeyConstants.ACTIVE_USER_LOGIN_TIMES).getData();
        reqVO.setActiveUserLoginTimes(Integer.parseInt(configDTO.getValue()));
        List<DeptDO> list = deptMapper.selectChildDeptList(DeptSearchVO.builder().deptId(reqVO.getDeptId()).userAttr(1).level(2).build());
        if(list.isEmpty()) return new PageResult<>();
        Map<Long, DeptDO> map = list.stream().collect(Collectors.toMap(DeptDO::getId, Function.identity()));
        reqVO.setChildDeptIds(new ArrayList<>(map.keySet()));
        userMapper.getUserStatDetail(page, reqVO);
        page.getRecords().forEach(e->e.setDeptName(map.get(e.getDeptId()).getName()));
        return new PageResult<>(page.getRecords(), page.getTotal());
    }

    @Override
    public Boolean isAdmin() {
        return GlobalConstants.ADMIN.equalsIgnoreCase(this.getUser(WebFrameworkUtils.getLoginUserId()).getUsername());
    }

    /**
     * 对密码进行加密
     *
     * @param password 密码
     * @return 加密后的密码
     */
    private String encodePassword(String password) {
        return passwordEncoder.encode(password);
    }

    @Override
    public AdminUserDO getUserData(Long id) {
        return userMapper.getUserData(id);
    }

    public List<AdminUserDO> getUserListByUserName(List<String> userNames) {
        return userMapper.getUserListByUserName(userNames);
    }

    public UserFirLoginRespVO isUpdatePassword(Long userId) {
        UserFirLoginRespVO loginRespVO = new UserFirLoginRespVO();
        loginRespVO.setStatus(false);
        AdminUserDO userDO = userMapper.getUserData(userId);
        if(userDO.getFirLogin() != null && userDO.getFirLogin().equals(1)) {
            loginRespVO.setStatus(true);
            loginRespVO.setData("用户首次登录请修改密码");
            return loginRespVO;
        }

        String validDayStr = userMapper.getPasswordValidDay("passwordValid");
        Integer validDay = 180;
        if(StringUtils.isNotBlank(validDayStr)) {
            validDay = Integer.parseInt(validDayStr);
        }
        long day = DateUtils.betweenNowDay(userDO.getUpdatePasswordTime());
        if(day > validDay) {
            loginRespVO.setStatus(true);
            loginRespVO.setData("用户密码有效期过期请修改密码");
            return loginRespVO;
        }
        return loginRespVO;
    }

}
